<template>
  <div class="k-code-wrapper">
    <codemirror
      ref="codeRef"
      v-model="codeText"
      v-bind="$attrs"
      class="k-code"
      :style="{ 'width': '100%', 'padding-right': '15px', 'height': '100%', 'min-height': '200px' }"
      :autofocus="true"
      :indent-with-tab="true"
      :tab-size="4"
      :extensions="extensions"
    />
    <div class="k-code-tools">
      <slot name="tools" />
    </div>
  </div>
</template>

<script setup lang="ts" name="ArcoCode">
  import type { Extension } from '@codemirror/state'
  import { html } from '@codemirror/lang-html'
  import { javascript } from '@codemirror/lang-javascript'
  import { json } from '@codemirror/lang-json'
  import { xml } from '@codemirror/lang-xml'
  import { oneDark } from '@codemirror/theme-one-dark'
  import { Codemirror } from 'vue-codemirror'
  import vkBeautify from 'vkbeautify'
  import { html_beautify as HtmlFormatter, js_beautify as JsFormatter } from 'js-beautify'
  import { PropType } from 'vue'
  import { isEmpty } from 'lodash'

  defineOptions({
    name: 'KCode'
  })
  type LangType = 'xml' | 'html' | 'javascript' | 'json' | 'txt'
  const props = defineProps({
    code: {
      type: String,
      require: true,
      default: ''
    },
    language: {
      type: String as PropType<LangType>,
      require: true,
      default: 'json'
    }
  })
  const codeRef = ref<HTMLElement | undefined>()
  const { code, language } = toRefs(props)
  const languageType = { xml, html, javascript, json, txt: json }
  const formatterFun: Record<string, any> = {
    html: HtmlFormatter,
    javascript: JsFormatter
  }

  function formatterCode(code: string, lang: LangType) {
    if (isEmpty(code) && lang === 'json') {
      code = '{}'
    }
    if (['xml', 'json', 'txt'].includes(lang)) {
      return vkBeautify.json(code)
    }
    return formatterFun[lang](code.trim())
  }
  const codeText = ref<string>()
  const extensions = ref<Extension>()
  watchEffect(() => {
    codeText.value = formatterCode(code.value, language.value)
    extensions.value = [oneDark, languageType[language.value as keyof typeof languageType]()]
  })
</script>

<style lang="less" scoped>
  .k-code-wrapper {
    position: relative;
    .k-code {
      :deep(*) {
        font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;
        font-size: 14px;
        font-weight: bold;
      }
    }
    .k-code-tools {
      position: absolute;
      top: 10px;
      right: 10px;
    }
  }
</style>